package com.ly.mp.dal.comm.config;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.jta.atomikos.AtomikosDependsOnBeanFactoryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;

import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.atomikos.icatch.config.UserTransactionService;
import com.atomikos.icatch.config.UserTransactionServiceImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.ly.mp.dal.comm.config.condition.TransactionPolicyJta;
import com.ly.mp.dal.comm.jdbc.DynamicDataSource;

@Configuration
@Conditional({TransactionPolicyJta.class})
@EnableTransactionManagement(proxyTargetClass = true)
@ImportResource({"classpath:ly-mp-readdb.xml"})
public class MpDataBaseJtaConfiguration {
    private static final Logger logger = LoggerFactory.getLogger(MpDataBaseJtaConfiguration.class);
    private Map<Object, Object> targetDataSources = new HashMap();

    @PostConstruct
    public void init() {
        this.targetDataSources.forEach((key, value) -> {
            try {
                ((DruidXADataSource) ((AtomikosDataSourceBean) value).getXaDataSource()).init();
                ((AtomikosDataSourceBean) value).init();
            } catch (SQLException var3) {
                var3.printStackTrace();
            }

        });
    }

    @PreDestroy
    public void close() {
        this.targetDataSources.forEach((key, value) -> {
            ((DruidXADataSource) ((AtomikosDataSourceBean) value).getXaDataSource()).close();
            ((AtomikosDataSourceBean) value).close();
        });
    }

    @Bean(name = {"dataSource"})
    public DataSource dynamicDataSource(BaseDataSourceInfo baseInfo, DatabaseSet dbSet) {
        DynamicDataSource dataSource = new DynamicDataSource();
        Iterator<DataSourceInfo> var6 = dbSet.getDataSourceInfo().iterator();

        while (var6.hasNext()) {
            DataSourceInfo dbInfo = var6.next();
            DruidXADataSource druidDataSource = new DruidXADataSource();
            BeanUtils.copyProperties(baseInfo, druidDataSource);
            BeanUtils.copyProperties(dbInfo, druidDataSource);
            if (dbInfo.getUrl().contains("oracle")) {
                druidDataSource.setValidationQuery("select 1 from dual");
            } else {
                druidDataSource.setValidationQuery("select 1");
            }

            try {
                AtomikosDataSourceBean xads = new AtomikosDataSourceBean();
                xads.setUniqueResourceName(dbInfo.getName()); // 设置bean的名称
                xads.setXaDataSource(druidDataSource); // 设置Xa数据源
                xads.setPoolSize(10);
                xads.setMinPoolSize(10);
                xads.setMaxPoolSize(100);
                xads.setBorrowConnectionTimeout(3000);
                xads.setTestQuery(druidDataSource.getValidationQuery());
                xads.setMaintenanceInterval(100);
                druidDataSource.init();
                targetDataSources.put(dbInfo.getName() + "_writeDBKey", xads);
            } catch (SQLException var10) {
                logger.error(var10.getMessage(), var10);
            }
        }

        dataSource.setDefaultTargetDataSource(targetDataSources.get(dbSet.getDefaultKey()));
        dataSource.setTargetDataSources(targetDataSources);
        return dataSource;
    }

    @Bean(initMethod = "init", destroyMethod = "shutdownForce")
    @ConditionalOnMissingBean({UserTransactionService.class})
    public UserTransactionServiceImp userTransactionService() {
        return new UserTransactionServiceImp();
    }

    @Bean(initMethod = "init", destroyMethod = "close")
    @ConditionalOnMissingBean
    public UserTransactionManager atomikosTransactionManager() {
        UserTransactionManager manager = new UserTransactionManager();
        manager.setStartupTransactionService(true);
        manager.setForceShutdown(false);
        return manager;
    }

    @Bean
    @ConditionalOnMissingBean
    public static AtomikosDependsOnBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
        return new AtomikosDependsOnBeanFactoryPostProcessor();
    }

    @Bean
    public JtaTransactionManager transactionManager(UserTransaction userTransaction,
            TransactionManager transactionManager) {
        return new JtaTransactionManager(userTransaction, transactionManager);
    }
}